package com.ruoyi.business.modbus.monitor;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * 网络稳定性监控器
 * 记录和分析网络连接的稳定性
 * 
 * @author ruoyi
 * @date 2024-01-01
 */
@Component
public class NetworkStabilityMonitor {
    
    private static final Logger log = LoggerFactory.getLogger(NetworkStabilityMonitor.class);
    
    // 连接统计信息
    final Map<String, ConnectionStats> deviceStats = new ConcurrentHashMap<>();
    
    // 稳定性判断阈值
    private static final double STABLE_SUCCESS_RATE = 0.9; // 90%成功率
    private static final long STABLE_AVG_RESPONSE_TIME = 1000L; // 1秒平均响应时间
    private static final long STABLE_NO_FAILURE_TIME = 5 * 60 * 1000L; // 5分钟内无失败
    private static final int MIN_SAMPLES = 10; // 最少样本数
    private static final int MAX_RESPONSE_SAMPLES = 100; // 最大响应时间样本数
    
    /**
     * 连接统计信息
     */
    public static class ConnectionStats {
        private int totalAttempts = 0;
        private int successfulAttempts = 0;
        private long lastSuccessTime = 0;
        private long lastFailureTime = 0;
        private final List<Long> responseTimes = new CopyOnWriteArrayList<>();
        private final long createTime = System.currentTimeMillis();
        // 设备IP和端口信息
        private String ipAddress = null;
        private Integer port = null;
        
        /**
         * 获取成功率
         */
        public double getSuccessRate() {
            return totalAttempts == 0 ? 0.0 : (double) successfulAttempts / totalAttempts;
        }
        
        /**
         * 获取平均响应时间
         */
        public double getAverageResponseTime() {
            if (responseTimes.isEmpty()) {
                return 0.0;
            }
            return responseTimes.stream().mapToLong(Long::longValue).average().orElse(0.0);
        }
        
        /**
         * 获取最近失败时间间隔
         */
        public long getTimeSinceLastFailure() {
            return lastFailureTime == 0 ? Long.MAX_VALUE : System.currentTimeMillis() - lastFailureTime;
        }
        
        /**
         * 获取响应时间方差（抖动）
         */
        public double getResponseTimeVariance() {
            if (responseTimes.size() < 2) {
                return 0.0;
            }
            
            double mean = getAverageResponseTime();
            double variance = 0.0;
            
            for (Long time : responseTimes) {
                variance += Math.pow(time - mean, 2);
            }
            
            return variance / responseTimes.size();
        }
        
        /**
         * 获取响应时间标准差（抖动）
         */
        public double getResponseTimeJitter() {
            return Math.sqrt(getResponseTimeVariance());
        }
        
        // Getters
        public int getTotalAttempts() { return totalAttempts; }
        public int getSuccessfulAttempts() { return successfulAttempts; }
        public long getLastSuccessTime() { return lastSuccessTime; }
        public long getLastFailureTime() { return lastFailureTime; }
        public List<Long> getResponseTimes() { return responseTimes; }
        public long getCreateTime() { return createTime; }
        public int getFailureCount() { return totalAttempts - successfulAttempts; }
        public String getIpAddress() { return ipAddress; }
        public Integer getPort() { return port; }
        public void setIpAddress(String ipAddress) { this.ipAddress = ipAddress; }
        public void setPort(Integer port) { this.port = port; }
    }
    
    /**
     * 记录连接尝试结果
     * 
     * @param deviceSN 设备编码
     * @param success 是否成功
     * @param responseTime 响应时间（毫秒）
     */
    public void recordConnectionAttempt(String deviceSN, boolean success, long responseTime) {
        recordConnectionAttempt(deviceSN, success, responseTime, null, null);
    }
    
    /**
     * 记录连接尝试结果（包含IP和端口）
     * 
     * @param deviceSN 设备编码
     * @param success 是否成功
     * @param responseTime 响应时间（毫秒）
     * @param ipAddress IP地址
     * @param port 端口号
     */
    public void recordConnectionAttempt(String deviceSN, boolean success, long responseTime, 
                                       String ipAddress, Integer port) {
        ConnectionStats stats = deviceStats.computeIfAbsent(deviceSN, k -> {
            log.debug("开始监控设备网络稳定性: {}", k);
            return new ConnectionStats();
        });
        
        synchronized (stats) {
            // 更新IP和端口信息（如果提供了的话）
            if (ipAddress != null) {
                stats.ipAddress = ipAddress;
            }
            if (port != null) {
                stats.port = port;
            }
            
            stats.totalAttempts++;
            
            if (success) {
                stats.successfulAttempts++;
                stats.lastSuccessTime = System.currentTimeMillis();
                
                // 记录响应时间
                stats.responseTimes.add(responseTime);
                
                // 保持最近的响应时间样本
                if (stats.responseTimes.size() > MAX_RESPONSE_SAMPLES) {
                    stats.responseTimes.remove(0);
                }
                
                double successRatePercent = Math.round(stats.getSuccessRate() * 1000) / 10.0;
                log.trace("记录成功连接: 设备={}, 响应时间={}ms, 成功率={}%, IP={}, 端口={}", 
                    deviceSN, responseTime, successRatePercent, ipAddress, port);
                
            } else {
                stats.lastFailureTime = System.currentTimeMillis();
                double successRatePercent = Math.round(stats.getSuccessRate() * 1000) / 10.0;
                log.debug("记录失败连接: 设备={}, 总尝试={}, 成功率={}%, IP={}, 端口={}", 
                    deviceSN, stats.totalAttempts, successRatePercent, ipAddress, port);
            }
        }
    }
    
    /**
     * 判断网络是否稳定
     * 
     * @param deviceSN 设备编码
     * @return 网络稳定性结果
     */
    public NetworkStabilityResult isNetworkStable(String deviceSN) {
        ConnectionStats stats = deviceStats.get(deviceSN);
        
        if (stats == null || stats.totalAttempts < MIN_SAMPLES) {
            return new NetworkStabilityResult(false, "数据样本不足", stats);
        }
        
        // 成功率检查
        double successRate = stats.getSuccessRate();
        if (successRate < STABLE_SUCCESS_RATE) {
            return new NetworkStabilityResult(false, 
                String.format("成功率过低: %.1f%% < %.1f%%", successRate * 100, STABLE_SUCCESS_RATE * 100), 
                stats);
        }
        
        // 平均响应时间检查
        double avgResponseTime = stats.getAverageResponseTime();
        if (avgResponseTime > STABLE_AVG_RESPONSE_TIME) {
            return new NetworkStabilityResult(false, 
                String.format("平均响应时间过长: %.0fms > %dms", avgResponseTime, STABLE_AVG_RESPONSE_TIME), 
                stats);
        }
        
        // 最近失败时间检查
        long timeSinceLastFailure = stats.getTimeSinceLastFailure();
        if (timeSinceLastFailure < STABLE_NO_FAILURE_TIME) {
            return new NetworkStabilityResult(false, 
                String.format("最近有失败: %.1f分钟前 < %.1f分钟", 
                    timeSinceLastFailure / 60000.0, STABLE_NO_FAILURE_TIME / 60000.0), 
                stats);
        }
        
        return new NetworkStabilityResult(true, "网络稳定", stats);
    }
    
    /**
     * 获取设备网络质量等级
     * 
     * @param deviceSN 设备编码
     * @return 质量等级
     */
    public String getNetworkQualityLevel(String deviceSN) {
        ConnectionStats stats = deviceStats.get(deviceSN);
        
        if (stats == null || stats.totalAttempts < MIN_SAMPLES) {
            return "未知";
        }
        
        double successRate = stats.getSuccessRate();
        double avgResponseTime = stats.getAverageResponseTime();
        //double jitter = stats.getResponseTimeJitter();
        
        if (successRate > 0.99 && avgResponseTime < 500) {
            return "优秀";
        } else if (successRate > 0.95 && avgResponseTime < 1000) {
            return "良好";
        } else if (successRate > 0.90 && avgResponseTime < 2000) {
            return "一般";
        } else {
            return "较差";
        }
    }
    
    /**
     * 获取设备统计信息
     * 
     * @param deviceSN 设备编码
     * @return 统计信息
     */
    public Map<String, Object> getDeviceNetworkStats(String deviceSN) {
        ConnectionStats stats = deviceStats.get(deviceSN);
        
        if (stats == null) {
            return Map.of("error", "设备不存在");
        }
        
        NetworkStabilityResult stability = isNetworkStable(deviceSN);
        
        Map<String, Object> result = new ConcurrentHashMap<>();
        result.put("deviceSN", deviceSN);
        result.put("totalAttempts", stats.getTotalAttempts());
        result.put("successfulAttempts", stats.getSuccessfulAttempts());
        result.put("failureCount", stats.getFailureCount());
        result.put("successRate", Math.round(stats.getSuccessRate() * 10000) / 100.0); // 保留2位小数
        result.put("averageResponseTime", Math.round(stats.getAverageResponseTime() * 100) / 100.0);
        result.put("responseTimeJitter", Math.round(stats.getResponseTimeJitter() * 100) / 100.0);
        result.put("lastSuccessTime", stats.getLastSuccessTime());
        result.put("lastFailureTime", stats.getLastFailureTime());
        result.put("timeSinceLastFailure", stats.getTimeSinceLastFailure());
        result.put("createTime", stats.getCreateTime());
        result.put("monitoringDuration", System.currentTimeMillis() - stats.getCreateTime());
        result.put("isStable", stability.isStable());
        result.put("stabilityReason", stability.getReason());
        result.put("qualityLevel", getNetworkQualityLevel(deviceSN));
        
        // 添加IP和端口信息
        result.put("ipAddress", stats.getIpAddress() != null ? stats.getIpAddress() : "-");
        result.put("port", stats.getPort() != null ? stats.getPort() : "-");
        
        return result;
    }
    
    /**
     * 获取所有设备的网络统计概览
     * 
     * @return 统计概览
     */
    public Map<String, Object> getAllDevicesNetworkOverview() {
        Map<String, Object> overview = new ConcurrentHashMap<>();
        
        int totalDevices = deviceStats.size();
        long stableDevices = deviceStats.keySet().stream()
                .mapToLong(deviceSN -> isNetworkStable(deviceSN).isStable() ? 1 : 0)
                .sum();
        
        overview.put("totalDevices", totalDevices);
        overview.put("stableDevices", stableDevices);
        overview.put("unstableDevices", totalDevices - stableDevices);
        overview.put("stabilityRate", totalDevices == 0 ? 0.0 : 
            Math.round((double) stableDevices / totalDevices * 10000) / 100.0);
        
        // 各设备的简要状态
        Map<String, Object> deviceStatus = new ConcurrentHashMap<>();
        for (String deviceSN : deviceStats.keySet()) {
            NetworkStabilityResult result = isNetworkStable(deviceSN);
            deviceStatus.put(deviceSN, Map.of(
                "stable", result.isStable(),
                "quality", getNetworkQualityLevel(deviceSN),
                "reason", result.getReason()
            ));
        }
        overview.put("deviceStatus", deviceStatus);
        
        return overview;
    }
    
    /**
     * 清除设备监控数据
     * 
     * @param deviceSN 设备编码
     */
    public void clearDeviceStats(String deviceSN) {
        ConnectionStats removed = deviceStats.remove(deviceSN);
        if (removed != null) {
            log.info("清除设备网络监控数据: {}", deviceSN);
        }
    }
    
    /**
     * 清除所有监控数据
     */
    public void clearAllStats() {
        int count = deviceStats.size();
        deviceStats.clear();
        log.info("清除所有网络监控数据，共 {} 个设备", count);
    }
    
    /**
     * 网络稳定性结果
     */
    public static class NetworkStabilityResult {
        private final boolean stable;
        private final String reason;
        private final ConnectionStats stats;
        
        public NetworkStabilityResult(boolean stable, String reason, ConnectionStats stats) {
            this.stable = stable;
            this.reason = reason;
            this.stats = stats;
        }
        
        public boolean isStable() { return stable; }
        public String getReason() { return reason; }
        public ConnectionStats getStats() { return stats; }
    }
}
